#include "msgping.h"
#include "utils/gradeutils.h"
#include "gkadpingiface.h"
#include "kademliamain.h"

#include <string>
#include <sstream>

using namespace gKad;
using namespace std;

MsgPing::MsgPing(IAppAPI *iApi) {
	this->iApi = iApi;
}

MsgPing::~MsgPing() {
	CloseHandle(waitEvent);

	iApi->RemoveListener(l_appId);
}

void MsgPing::Init() {
	waitEvent = CreateEvent(NULL, false, false, NULL);

	iApi->AddAnotherListener(static_cast<IListener *> (this), &l_appId);
}

bool MsgPing::SendPing(_GUID dest, int timeout) {
	struct s_ping	pingData;
	IServer			*server;

	Init();

	// get server reference
	iApi->GetServer(&server);

	// fill ping data
	pingData.dstAddr = dest;
	pingData.srcApp = l_appId;
	pingData.alive = false;
	server->Address(&pingData.srcAddr);

	IStream *stream;
	iApi->CreateStream(&stream);
	stream->Write(&pingData, sizeof(pingData), NULL);
	
	// send
	int i_result = iApi->InjectCapsule("gkadping.dll", stream, pingData.dstAddr, InjectMaxTTL);
	if (i_result != 0) {
		KademliaMain::GetInstance()->WriteLog("[ERROR] Couldn't send ping capsule.");
		return false;
	}

	// wait for response
	if (WaitForSingleObject(waitEvent, timeout) == WAIT_OBJECT_0)
		return true;

	return false;
}

void __stdcall MsgPing::OnSendData(TAppID appId, IStream *stream) {
#ifdef _DEBUG
	KademliaMain::GetInstance()->WriteLog("Capsule back...");
#endif

	SetEvent(waitEvent);
}

HRESULT __stdcall MsgPing::QueryInterface(const IID &riid,void **ppvObj) {
	// Always set out parameter to NULL, validating it first.
	if (!ppvObj)
       return E_INVALIDARG;

	*ppvObj = NULL;
	
	if (riid == IID_IListener) {
       *ppvObj = static_cast<IListener*>(this);
        AddRef();
        return NOERROR;

	} else if (riid == IID_IUnknown) {
        *ppvObj = static_cast<IUnknown*>(this);
        AddRef();
        return NOERROR;
	}

    return E_NOINTERFACE;
}